#Seguridad.
#Se definen los módulos y la relación entre ellos en el método "load_modules",
#este utiliza "create_or_update_modulo(attributes,nom_padre='')" para crear o
#actualizar los módulos. Una vez cargados todos los módulos, se cargan
#los controllers y sus acciones con el metodo "load_controllers_actions".
#La palabras reservadas son:
#
##DESC: en la parte superior del controller, antes de cualquier acción o (método)
#para asignar una descripción para el controller, al lado derecho del nombre de una
#acción para asignar una descripción a esta.
#En ambos casos es opcional, en caso de su ausencia se utiliza el nombre como la
#descripción, en caso que la acción pertenezca a scaffold, se provee una descripción predeterminada.
#
##MODULE: en la parte superior del controller (bajo de #DESC: si esta presente)
# y antes de cualquier acción para determinar a que módulo pertenece el controller.
# En caso de ausencia de esta palabra, el controller y todas sus acciones no serán
# controladas.

##IGNORE: al lado derecho del nombre de las acciones que no necesiten ser controladas.
#Si en una primera ejecución, una acción es controllada, y en una segunda ejecución la
#acción posee esta palabra donde se indico, la acción y todos los permisos relacionados
#son eliminados
##Ej:
#class UsuariosController < ApplicationController
#  before_filter  :set_modulos, :only=>[:show,:micuenta,:edit]
#  #DESC: Acciones relacionadas a los usuarios
#  #MODULE: Gestión de personas
#
#  def lugar_actual #IGNORE
#  end
#
#  # GET /usuarios
#  # GET /usuarios.xml
#  def index
#  end
#
#  def micuenta #DESC: Acceder a la cuenta personal del usuario.
#  end
# end
#
# Otras palabras "reservadas" son "private" y "protected"
# Si se encuentra alguna de estas palabras, los métodos situados por debajo son
# ignorados, por lo cual no es necesario colocar la palabra #IGNORE
# OBS.: TODAS LAS PALABRAS SON CASE SENSITIVE

def get_module_and_desc(datos)
  module_nom=controller_desc=''
  return if datos.empty?
  if datos.first.include?('DESC')
    controller_desc=datos.delete_at(0)
    controller_desc=controller_desc.gsub('#','').gsub('DESC:','')
    module_nom  = (!datos.first.nil? and datos.first.include?("MODULE")) ? datos.delete_at(0) : ''
  elsif datos.first.include?('MODULE')
    module_nom= datos.delete_at(0)
  end
  module_nom=module_nom.gsub('#','').gsub('MODULE:','')

  [module_nom.strip,controller_desc.strip]
end

def get_datos(file)
  datos = file.lines.grep(/DESC|MODULE| def |private|protected/).collect{|x| x.strip}
  
  i=datos.index("private")
  datos.slice!(i,datos.length) unless i.nil?
  i=datos.index("protected")
  datos.slice!(i,datos.length)  unless i.nil?
  datos.delete_if{|x| x.match(/ create| update/)}

  ignorados=datos.select{|x| x.match(/IGNORE/)}
  datos.delete_if{|x| x.match(/IGNORE/)}
  
  [datos,ignorados]
end

def add_actions(controller, acciones,scaffold_desc)
  acciones.each do |accion|
    n,d=accion.gsub('def ','').split('#DESC:').collect{|x| x.strip}
    a=Accion.find_or_create_by_nombre_and_controller_id(n,controller.id)
    d =  scaffold_desc[n] if d.blank?
    a.descripcion=d
    a.save!
  end
end

def delete_actions(controller, acciones)
  acciones.each do |accion|
    n=accion.gsub('def ','').gsub('#IGNORE','').strip
    a=Accion.find_by_nombre_and_controller_id(n,controller.id)
    next if a.nil?
    cant=Permiso.delete_all("accion_id=#{a.id}")
    a.delete
    puts "\n\n**************************************************************"
    puts "Accion eliminada => #{a.inspect}"
    puts "Cantidad de permisos relacionados eliminados: => #{cant}"
    puts "**************************************************************\n\n"
  end
end

def faltan_datos?(mod,datos,file,module_nom)
  if mod.nil?
    r=ignorado_msg("IGNORADO: \n-No se definio el módulo al que pertenece.\n- O No se encontro el módulo al que pertenece.\n NOMBRE DEL MODULO: #{module_nom}",file)
  elsif  datos.empty?
    r=ignorado_msg("IGNORADO: \n-El controller no posee acciones controladas",file)
  end
  r
end

def ignorado_msg(msg,file)
  puts msg
  file.close
  true
end

def create_or_update_modulo(attributes,nom_padre='')
  m=Modulo.find_by_nombre(nom_padre,:select=>:id) unless nom_padre.empty?
  id=m.try(:id)
  m=Modulo.find_or_create_by_nombre(attributes[:nombre])
  m.update_attributes!(attributes.merge(:modulo_id=>id))
end

def load_modules
  puts "Carga de módulos."
  puts "================="
  [
    {:nombre=>"Gestión de personas",:descripcion=>"Todo lo relacionado a la gestión del personal (laboral,personal y acceso al sistema).",:orden=>1},
    {:nombre=>"Gestión Salarial",:descripcion=>"Todo lo relaiconado a los salarios (movimientos,recibos,etc.)",:orden=>2},
    {:nombre=>"Evaluaciones",:descripcion=>"Todo lo relaiconado a evaluaciones.",:orden=>3},
    {:nombre=>"Utilitarios",:descripcion=>"Utilitarios varios (importaciones, solicitudes, etc.)",:orden=>4},
    {:nombre=>"Horarios",:descripcion=>"Todo lo relaiconado a la getión de horarios (control de marcaciones,etc.)",:orden=>5},
    {:nombre=>"Configuraciones",:descripcion=>"Configuracion General del sistema.",:orden=>6}].each do |attributes|
    create_or_update_modulo(attributes)
  end

  [
    {:nombre=>"Datos Personales",:descripcion=>"Muestra Datos Personales",:orden=>1},
    {:nombre=>"Datos Laborales",:descripcion=>"Muestra Datos Laborales",:orden=>3},
    {:nombre=>"Usuario",:descripcion=>"Muestra Datos de Usuario",:orden=>2}].each do |attributes|
    create_or_update_modulo(attributes,"Gestión de personas")
  end

  [
    {:nombre=>"Básicos",:descripcion=>"Muestra Datos Basicos",:orden=>1},
    {:nombre=>"Domicilio",:descripcion=>"Muestra Datos Domicilio",:orden=>2},
    {:nombre=>"Datos Familiares",:descripcion=>"Muestra Datos Familiares",:orden=>3},
    {:nombre=>"Formaciones",:descripcion=>"Muestra Datos Formaciones",:orden=>4},
    {:nombre=>"Idiomas",:descripcion=>"Muestra Datos Idiomas",:orden=>5},
    {:nombre=>"Documentos",:descripcion=>"Muestra Datos Documentos",:orden=>6},
    {:nombre=>"Pasatiempos",:descripcion=>"Muestra Datos Pasatiempos",:orden=>7},
    {:nombre=>"Ficha Médica",:descripcion=>"Muestra Datos ficha medica",:orden=>8}].each do |attributes|
    create_or_update_modulo(attributes,"Datos Personales")
  end

  [
    {:nombre=>"Datos Administrativos",:descripcion=>"Muestra Datos administrativos",:orden=>1},
    {:nombre=>"Historial Salarial",:descripcion=>"Muestra historial salarial",:orden=>2},
    {:nombre=>"Prestamos",:descripcion=>"Muestra Prestamos",:orden=>3},
    {:nombre=>"Historial Laboral",:descripcion=>"Muestra Historial Laboral",:orden=>4},
    {:nombre=>"Uniformes",:descripcion=>"Muestra Uniformes",:orden=>5},
    {:nombre=>"Horario Laboral",:descripcion=>"Muestra horarios",:orden=>6},
    {:nombre=>"Vacaciones",:descripcion=>"Muestra Vacaciones",:orden=>7},
    {:nombre=>"Resumen De Horas",:descripcion=>"Muestra Resument de horas",:orden=>8},
    {:nombre=>"Reconocimientos",:descripcion=>"Muestra Reconocimientos",:orden=>9}].each do |attributes|
    create_or_update_modulo(attributes,"Datos Laborales")
  end
  [
    {:nombre=>"Sesiones",:descripcion=>"Muestra sus sesiones",:orden=>1},
    {:nombre=>"Perfiles",:descripcion=>"Muestra sus perfiles",:orden=>2}].each do |attributes|
    create_or_update_modulo(attributes,"Usuario")
  end
end

def load_controllers_actions
  puts "Carga de Controllers => Acciones"
  puts "=================================="
  scaffold_desc={
    "index"=>"lista de registros",
    "new"=>"agregar registros",
    "edit"=>"editar registros",
    "destroy"=>"borrar registros",
    "show"=>"ver detalles de un registro"
  }
  Dir.chdir("#{RAILS_ROOT}/app/controllers")
  Dir.glob("*.rb") do |cont|
    file = File.new(cont, "r")
    controller_name = cont.gsub(/_controller.rb$/, "")
    puts "\n\n==========================="
    puts "Procesando #{controller_name}"
    datos,ignorados = get_datos(file)
    module_nom,controller_desc = get_module_and_desc(datos)
    mod = Modulo.find_by_nombre(module_nom)
    next if faltan_datos?(mod,datos,file,module_nom)
    control = Controller.find_or_create_by_nombre(controller_name)
    control.descripcion = controller_desc.empty? ? controller_name.humanize : controller_desc
    control.modulo_id = mod.id
    control.save!
    add_actions(control,datos,scaffold_desc)
    delete_actions(control,ignorados)
    file.close
  end #Dir.each
end

def create_super_powers
  puts "Creando Perfil administrador"
  puts "============================"
  p=Perfil.find_or_create_by_nombre("Administrador")
  p.modulo_ids=Modulo.all(:select=>:id).map(&:id)
  p.accion_ids=Accion.all(:select=>:id).map(&:id)
  p.save!
end
namespace :seguridad do
  desc "Carga los módulos y los controllers y acciones controladas"
  task :reload => :environment do
    load_modules
    load_controllers_actions
    create_super_powers
  end
end
